package net.kazed.nextaction.database;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;

public class SqlTemplate {

    private SQLiteDatabase db;

    /**
     * Constructor.
     * @param db Database.
     */
    public SqlTemplate(SQLiteDatabase db) {
        super();
        this.db = db;
    }
    
    /**
     * Query for a single result.
     * @param <T> Type if result.
     * @param tableName Table name.
     * @param projectionMap Projection map.
     * @param selectColumns Columns to select.
     * @param handler Maps record to result object of type T.
     * @return Query result.
     */
    public <T> T query(String tableName, Map<String, String> projectionMap, String[] selectColumns, QueryHandler<T> handler) {
        T result = null;
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        qb.setTables(tableName);
        qb.setProjectionMap(projectionMap);
        Cursor cursor = null;
        try {
            cursor = qb.query(db, selectColumns, null, null, null, null, null);
            result = handler.execute(cursor);
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        
        return result;
    }
    
    /**
     * Query for a single result.
     * @param <T> Type if result.
     * @param tableName Table name.
     * @param projectionMap Projection map.
     * @param selectColumns Columns to select.
     * @param where Where clause.
     * @param whereArguments Values for where clause.
     * @param handler Maps record to result object of type T.
     * @return Query result.
     */
    public <T> T query(String tableName, Map<String, String> projectionMap, String[] selectColumns,
                    String where, String[] whereArguments,
                    QueryHandler<T> handler) {
        T result = null;
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        qb.setTables(tableName);
        qb.setProjectionMap(projectionMap);
        Cursor cursor = null;
        try {
            cursor = qb.query(db, selectColumns, where, whereArguments, null, null, null);
            if (cursor.moveToFirst()) {
                result = handler.execute(cursor);
            }
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        
        return result;
    }
    
    /**
     * Query for a single result.
     * @param <T> Type if result.
     * @param tableName Table name.
     * @param projectionMap Projection map.
     * @param selectColumns Columns to select.
     * @param where Where clause.
     * @param whereArguments Values for where clause.
     * @param handler Maps record to result object of type T.
     * @return Query result.
     */
    public <T> List<T> queryList(String tableName, Map<String, String> projectionMap, String[] selectColumns,
                    String where, String[] whereArguments,
                    QueryHandler<T> handler) {
        List<T> list = new ArrayList<T>();
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        qb.setTables(tableName);
        qb.setProjectionMap(projectionMap);
        Cursor cursor = null;
        try {
            cursor = qb.query(db, selectColumns, where, whereArguments, null, null, null);
            if (cursor.moveToFirst()) {
                T result = handler.execute(cursor);
                if (result != null) {
                    list.add(result);
                }
            }
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        
        return list;
    }
    
    /**
     * Map record to object for single result.
     * @param <T> Type of result.
     */
    public static interface QueryHandler<T> {
        T execute(Cursor cursor);
    }

}
